﻿using System;
using System.Diagnostics;
using System.Threading;

namespace Safebrowsing
{
    /// <summary>
    /// Helper class for logging using System.Diagnostics.Trace class
    /// </summary>
    internal static class Logger
    {
        private const string CATEGORY_NAME = "SafebrowsingApi";
        private static readonly string PROCESS_NAME = Process.GetCurrentProcess().ProcessName;
        private static readonly TraceSwitch TRACE_SWITCH = new TraceSwitch("TraceLevelSwitch", null, "3");

        public static TraceLevel Level { set { TRACE_SWITCH.Level = value; } }

        public static void AddFileListener(string fileName)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(fileName));
        }

        public static void ClearListeners()
        {
            Trace.Listeners.Clear();
        }

        [Conditional("TRACE")]
        public static void Info(string format, params object[] args)
        {
            Info(string.Format(format, args));
        }

        [Conditional("TRACE")]
        public static void Info(string message)
        {
            if (TRACE_SWITCH.TraceInfo)
                TraceLine(TraceLevel.Info, message);
        }

        [Conditional("TRACE")]
        public static void Error(string format, params object[] args)
        {
            Error(string.Format(format, args));
        }

        [Conditional("TRACE")]
        public static void Error(string message)
        {
            if (TRACE_SWITCH.TraceError)
            {
                TraceLine(TraceLevel.Error, message);
                Flush();
            }
        }

        [Conditional("TRACE")]
        public static void Warn(string format, params object[] args)
        {
            Warn(string.Format(format, args));
        }

        [Conditional("TRACE")]
        public static void Warn(string message)
        {
            if (TRACE_SWITCH.TraceWarning)
            {
                TraceLine(TraceLevel.Warning, message);
                Flush();
            }
        }

        [Conditional("TRACE")]
        public static void Verbose(string format, params object[] args)
        {
            Verbose(string.Format(format, args));
        }

        [Conditional("TRACE")]
        public static void Verbose(string message)
        {
            if (TRACE_SWITCH.TraceVerbose)
                TraceLine(TraceLevel.Verbose, message);
        }

        /// <summary>
        /// Flushes log to the listeners
        /// </summary>
        public static void Flush()
        {
            Trace.Flush();
        }

        private static void TraceLine(TraceLevel level, string message)
        {
            string traceLevel;

            switch (level)
            {
                case TraceLevel.Error:
                    traceLevel = "ERROR:  ";
                    break;

                case TraceLevel.Warning:
                    traceLevel = "WARNING:";
                    break;

                case TraceLevel.Info:
                    traceLevel = "INFO:   ";
                    break;

                case TraceLevel.Verbose:
                    traceLevel = "VERBOSE:";
                    break;

                default:
                    traceLevel = "DEFAULT:";
                    break;
            }

            string finalMessage = string.Format(
                "{0}, {1}, {2}, {3}, {4}", traceLevel, PROCESS_NAME,
                Thread.CurrentThread.ManagedThreadId, DateTime.Now, message);

            Trace.WriteLine(finalMessage, CATEGORY_NAME);
        }
    }
}
